1 module targets.android;
2 import features.ldc;
3 import commons;
4 import std.net.curl;
5 import std.path;
6 
7 ///This is the one which will be installed when using the SDK.
8 enum TargetAndroidSDK = 35;
9 enum TargetAndroidNDK = "28.0.12433566";
10 enum TargetJavaJDK = "17.0.12";
11 ///Use a random Adb Port 
12 enum HipremeEngineAdbPort = "55565";
13 
14 private string getAndroidFlagsToolchains()
15 {
16 	enum AndroidSDKLibs = 35;
17 
18 	version(Windows)
19 		string system = "windows-x86_64";
20 	else version(linux)
21 		string system = "linux-x86_64";
22 	else version(OSX)
23 		string system = "darwin-x86_64";
24 	else static assert(false, "Your OS does not support android NDK installation.");
25 
26 	string toolsPath = buildNormalizedPath(configs["androidNdkPath"].str, "toolchains", "llvm", "prebuilt", system);
27 
28 	version(Windows)
29 	{
30 		import std.string:replace;
31 		return "-gcc=\""~buildNormalizedPath(toolsPath, "bin/aarch64-linux-android35-clang.cmd").replace("\\", "/") ~"\" " ~
32 		"-linker=\""~buildNormalizedPath(toolsPath, "bin/ld.lld.exe").replace("\\", "/") ~"\" " ~
33 		///Put the lib path for finding libandroid, liblog, libOpenSLES, libEGL and libGLESv3
34 		"-L-L\""~buildNormalizedPath(toolsPath, "sysroot/usr/lib/aarch64-linux-android/"~AndroidSDKLibs~"/").replace("\\", "/")~"\" "
35 		;
36 	}
37 	else
38 	{
39 		return "-gcc="~buildNormalizedPath(toolsPath, "bin/aarch64-linux-android35-clang") ~" " ~
40 		"-linker="~buildNormalizedPath(toolsPath, "bin/ld.lld") ~" " ~
41 		"-L-L"~buildNormalizedPath(toolsPath, "sysroot/usr/lib/aarch64-linux-android/"~AndroidSDKLibs~"/")
42 		;
43 	}
44 }
45 
46 private ChoiceResult runAndroidApplication(ref Terminal t)
47 {
48 	version(Windows)
49 	{
50 		string adb = buildNormalizedPath(configs["androidSdkPath"].str, "platform-tools", "adb.exe");
51 		string gradlew = "gradlew.bat";
52 	}
53 	else version(Posix)
54 	{
55 		string adb = buildNormalizedPath(configs["androidSdkPath"].str, "platform-tools", "adb");
56 		string gradlew = "./gradlew";
57 
58 		if(!makeFileExecutable(getHipPath("build", "android", "project", "gradlew")))
59 		{
60 			t.writelnError("Could not make gradlew executable.");
61 			return ChoiceResult.Error;
62 		}
63 	}
64 
65 	with(WorkingDir(getHipPath("build", "android", "project")))
66 	{
67 		if(t.wait(spawnShell(gradlew ~ " :app:assembleDebug")) != 0)
68 		{
69 			t.writelnError("Could not build Java code.");
70 			return ChoiceResult.Error;
71 		}
72 
73 		string adbInstall = adb~" install -r "~
74 			buildNormalizedPath(std.file.getcwd(), "app", "build", "outputs", "apk", "debug", "app-debug.apk");
75 
76 		t.writeln("Executing adb install: ", adbInstall);
77 		t.flush;
78 		environment["ANDROID_ADB_SERVER_PORT"] = HipremeEngineAdbPort;
79 		if(t.wait(spawnShell(adbInstall)) != 0)
80 		{
81 			t.writelnError("Could not install application to your device.");
82 			return ChoiceResult.Error;
83 		}
84 		if(t.wait(spawnShell(adb~" shell monkey -p com.hipremeengine.app 1")) != 0)
85 		{
86 			t.writelnHighlighted("Could not connect to Android's shell");
87 		}
88 	}
89 	//logcat -b all -v color com.hipremengine.app:D | findstr com.hipremeengine.app
90 	return ChoiceResult.Continue;
91 }
92 
93 ChoiceResult prepareAndroid(Choice* c, ref Terminal t, ref RealTimeConsoleInput input, in CompilationOptions cOpts)
94 {
95 	import features.android_ndk;
96 	import features.java_jdk;
97 	import features.android_ldc;
98 
99 	if(!JavaJDKFeature.getFeature(t, input, TargetVersion.parse(TargetJavaJDK)))
100 		return ChoiceResult.Error;
101 	if(!AndroidNDKFeature.getFeature(t, input, TargetVersion.parse(TargetAndroidNDK)))
102 		return ChoiceResult.Error;
103 
104 	executeGameRelease(t);
105 	putResourcesIn(t, getHipPath("build", "android", "project", "app", "src", "main", "assets"));
106 	outputTemplate(t, configs["gamePath"].str);
107 
108 	string ldcLibsPath = getAndroidLDCLibrariesPath.execute(t, input);
109 
110 	string nextReleaseFlags = "-defaultlib=phobos2-ldc,druntime-ldc " ~
111 		"-link-defaultlib-shared=false " ~
112 		"-L-L"~ ldcLibsPath ~" " ~
113 		"-L-rpath="~ ldcLibsPath~" ";
114 
115 	environment["DFLAGS"] = nextReleaseFlags ~ getAndroidFlagsToolchains();
116 	t.writeln(environment["DFLAGS"]);
117 	t.flush;
118 
119 	with(WorkingDir(configs["gamePath"].str))
120 	{
121 		ProjectDetails proj;
122 		if(waitRedub(t, DubArguments().command("build").arch("aarch64--linux-android").configuration("android").opts(cOpts), proj) != 0)
123 		{
124 			t.writelnError("Compilation failed.");
125 			return ChoiceResult.Error;
126 		}
127 
128 		string file = proj.getOutputFile();
129 		if(std.file.exists(file))
130 		{
131 			string newName = getHipPath("build", "android", "project", "app", "src", "main", "jniLibs", "arm64-v8a", "libhipreme_engine.so");
132 			t.writelnHighlighted("Renaming ", file, " to "~newName~" for compatibility");
133 			std.file.rename(
134 				file,
135 				newName
136 			);
137 		}
138 	}
139 
140 	return runAndroidApplication(t);
141 }